package com.scedu.service.impl;

import com.scedu.service.SignInService;
import com.scedu.utils.DateUtils;
import com.scedu.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;


@Service
@Transactional
@Slf4j
public class SignInServiceImpl implements SignInService {
    /**
     * 构建指定类型的Redis的key：u:sign:10000:202001
     */
    private static String buildSignKey(int aid, LocalDate date) {
        Date date1 = DateUtils.localDate2Date(date);
        return String.format("u:sign:%d:%s", aid, DateUtils.dateyyyymmTime(date1));
    }


    /**
     * 获取Date类型的当月的天数
     */
    private static int getDaysOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }









    /**
     * 用户签到
     *
     * @param cid  用户ID
     * @param date 日期
     * @return 之前的签到状态
     */
    @Override
    public boolean doSign(int cid, LocalDate date) {
        int offset = date.getDayOfMonth() - 1;
        return RedisUtils.setBit(buildSignKey(cid, date), offset, true);

    }

    /**
     * 检查用户是否签到
     *
     * @param aid  用户ID
     * @param date 日期
     * @return 当前的签到状态
     */
    @Override
    public boolean checkSign(int aid, LocalDate date) {
        int offset = date.getDayOfMonth() - 1;
        return RedisUtils.getBit(buildSignKey(aid, date), offset);
    }


    /**
     * 获取用户签到次数
     *
     * @param uid  用户ID
     * @param date 日期
     * @return 当月的签到次数
     */
    public long getSignCountByMonth(int uid, LocalDate date) {
        return RedisUtils.bitCount(buildSignKey(uid, date),0,-1);
    }

    /**
     * 获取当月连续签到次数
     *
     * @param uid  用户ID
     * @param date 日期
     * @return 当月连续签到次数
     */
    public long getContinuousSignCount(int uid, LocalDate date) {
        int signCount = 0;
        List<Long> list = RedisUtils.bitfield(buildSignKey(uid, date), date.lengthOfMonth(),0);
        log.info("-----------");
        for (Long aLong : list) {
            log.info(String.valueOf(aLong));
        }
        log.info("++++++++++++");
        if (list != null && list.size() > 0) {
            // 取低位连续不为0的个数即为连续签到次数，需考虑当天尚未签到的情况
            long v = list.get(0) == null ? 0 : list.get(0);
            log.info("v="+v);
            log.info(" date.getDayOfMonth()="+ date.getDayOfMonth());
            for (int i = 0; i < date.getDayOfMonth(); i++) {
                log.info("i="+i);
                log.info("v >> 1"+String.valueOf(v >> 1));
                log.info("v >> 1 << 1"+String.valueOf(v >> 1 << 1));
                if (v >> 1 << 1 == v) {
                    // 低位为0且非当天说明连续签到中断了
                    log.info("vv="+v);
                    if (i > 0) break;
                } else {
                    signCount += 1;
                }
                v >>= 1;
            }
        }
        return signCount;
    }

    @Override
    public LocalDate getFirstSignDate(int cid, LocalDate date) {
        return null;
    }

    /**
     * 获取当月签到情况
     *
     * @param uid  用户ID
     * @param date 日期
     * @return Key为签到日期，Value为签到状态的Map
     */
    public Map<String, Boolean> getSignInfo(int uid, LocalDate date) {
        Map<String, Boolean> signMap = new HashMap<>(date.getDayOfMonth());
        String type = String.format("u%d", date.lengthOfMonth());
        log.info("date="+date);
        log.info("date.getDayOfMonth()="+date.getDayOfMonth());
        log.info("date.lengthOfMonth()="+date.lengthOfMonth());
        List<Long> list = RedisUtils.bitfield(buildSignKey(uid, date), date.lengthOfMonth(),0);
        log.info("-----------");
        for (Long aLong : list) {
            log.info(String.valueOf(aLong));
        }
        log.info("++++++++++++");
        if (list != null && list.size() > 0) {
            // 由低位到高位，为0表示未签，为1表示已签
            long v = list.get(0) == null ? 0 : list.get(0);
            for (int i = date.lengthOfMonth(); i > 0; i--) {
                LocalDate d = date.withDayOfMonth(i);
                signMap.put(DateUtils.parseDateToStr( "yyyy-MM-dd",DateUtils.localDate2Date(d)), v >> 1 << 1 != v);
                v >>= 1;
            }
        }
        return signMap;
    }
}
